package com.hzy.context;


import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;

public class ClassPathUtils {

    /**
     * 从输入流中读取数据的通用方法
     * <p>
     * 此方法用于从给定路径的资源中读取数据，通过回调函数处理输入流它避免了直接
     * 返回输入流，而是通过参数化的类型安全地处理它适用于需要从资源文件中读取数据，
     * 但又不希望局限于特定返回类型的情况
     *
     * @param <T>                 泛型参数，指定返回值的类型
     * @param path                资源文件的路径字符串
     * @param inputStreamCallback 输入流回调对象，用于处理打开的输入流
     * @return T，回调函数处理输入流后返回的结果
     * @throws UncheckedIOException 如果文件未找到或读取过程中发生IO异常
     */
    public static <T> T readInputStream(String path, InputStreamCallback<T> inputStreamCallback) {
        // 移除路径前的斜杠，以防止类路径资源加载问题
        if (path.startsWith("/")) {
            path = path.substring(1);
        }
        try (InputStream input = getContextClassLoader().getResourceAsStream(path)) {
            // 如果输入流为null，表示未找到资源文件，抛出FileNotFoundException
            if (input == null) {
                throw new FileNotFoundException("File not found in classpath: " + path);
            }
            // 使用回调函数处理输入流，并返回处理结果
            return inputStreamCallback.doWithInputStream(input);
        } catch (IOException e) {
            // 打印IO异常的堆栈跟踪信息
            e.printStackTrace();
            // 抛出运行时IO异常，使得调用者无需处理检查型异常
            throw new UncheckedIOException(e);
        }
    }


    /**
     * 从指定路径读取字符串
     *
     * @param path 资源的路径
     * @return 读取到的字符串
     */
    public static String readString(String path) {
        // 使用Lambda表达式处理输入流，读取所有字节并转换为UTF-8字符串
        return readInputStream(path, (input) -> {
            byte[] data = input.readAllBytes(); // 读取输入流中的所有字节
            return new String(data, StandardCharsets.UTF_8); // 将字节数组转换为UTF-8编码的字符串
        });
    }

    /**
     * 获取当前线程的上下文类加载器
     * <p>
     * 如果当前线程没有显式设置上下文类加载器，则使用系统类加载器或其父类加载器
     * 这个方法解释了为什么需要获取当前线程的上下文类加载器，并且提供了在无法获取时的备选方案
     *
     * @return ClassLoader 当前线程的上下文类加载器，如果无法获取，则返回系统类加载器或其父类加载器
     */
    static ClassLoader getContextClassLoader() {
        // 初始化类加载器为null，准备后续获取或赋值
        ClassLoader cl = null;

        // 尝试获取当前线程的上下文类加载器
        cl = Thread.currentThread().getContextClassLoader();

        // 如果获取到的类加载器为null，则尝试使用当前类所在的类加载器作为备选
        if (cl == null) {
            cl = ClassPathUtils.class.getClassLoader();
        }

        // 返回最终确定的类加载器
        return cl;
    }
}
